#include "Socket.hpp"
#include "InetAddr.hpp"
#include <cstring>
#include <sys/epoll.h>
#include <memory>
using namespace socket_ns;

class EpollServer
{
    const static int N = 64;
public:
    EpollServer(uint16_t port)
        : _port(port), _listenSock(std::make_unique<TcpSocket>()), _epfd(defaultFd)
    {
        // 1. 创建tcp服务端
        _listenSock->BuildListenSocket(InetAddr(port, "0"));

        //2. 创建epoll
        _epfd = ::epoll_create(128);
        if(_epfd < 0)
        {
            LOG(FATAL, "epoll fd create fail\n");
            exit(SOCKET_ERR);
        }
        LOG(INFO, "epoll fd create success!, epfd : %d\n", _epfd);

        //3.为epfd添加对listensock的关心
        struct epoll_event ev;
        ev.events = EPOLLIN;
        ev.data.fd = _listenSock->Sockfd();
        int n = ::epoll_ctl(_epfd, EPOLL_CTL_ADD, _listenSock->Sockfd(), &ev);
        if(n < 0)
        {
            LOG(FATAL, "设置 epoll 对 listenSock 的关心 失败\n");
            exit(5);
        }
        LOG(INFO, "设置 epoll 对 listenSock 的关心 成功\n");
    }

    void AcceptClient()
    {
        InetAddr clientAddr;
        int newfd = _listenSock->Accepter(clientAddr); // 这里一定不会被阻塞
        LOG(INFO, "get new link, fd : %d, addr : [%s:%d]\n", newfd, clientAddr.IP().c_str(), clientAddr.Port());

        struct epoll_event ev;
        ev.events = EPOLLIN;
        ev.data.fd = newfd;
        int n = ::epoll_ctl(_epfd, EPOLL_CTL_ADD, newfd, &ev);
        if(n < 0)
        {
            LOG(ERROR, "设置 epoll 对 newfd 的关心 失败\n");
            exit(5);
        }
        LOG(INFO, "设置 epoll 对 newfd 的关心 成功\n");

    }
    void ServiceIO(int fd)
    {
        char buff[1024];
        ssize_t n = ::read(fd, buff, sizeof(buff) - 1);
        if (n > 0)
        {
            buff[n] = 0;
            std::cout << "client say#" << buff << std::endl;
            std::string message = buff;
            ::send(fd, message.c_str(), message.size(), 0);
        }
        else if (n == 0)
        {
            LOG(INFO, "%d is closed\n", fd);
            ::epoll_ctl(_epfd, EPOLL_CTL_DEL, fd, nullptr);
            ::close(fd);
            LOG(INFO, "成功取消对 %d 的关心\n", fd);
        }
        else
        {
            LOG(ERROR, "recv error\n");
            ::epoll_ctl(_epfd, EPOLL_CTL_DEL, fd, nullptr);
            ::close(fd);
            LOG(INFO, "成功取消对 %d 的关心\n", fd);
        }
    }
    void HandlerEvent(int n)
    {
        for (int i = 0; i < n; i++)
        {
            uint32_t events = epArr[i].events;
            int fd = epArr[i].data.fd;
            if(events & EPOLLIN)
            {
                if(fd == _listenSock->Sockfd())
                {
                    AcceptClient();
                }
                else
                {
                    ServiceIO(fd);
                }
            }
        }
    }
    void Loop()
    {

        while (true)
        {
            int timeout = -1;
            int n = ::epoll_wait(_epfd, epArr, N, timeout);
            switch (n)
            {
            case 0:
                LOG(INFO, "time out.... \n");
                break;
            case -1:
                LOG(ERROR, "select error\n");
                break;
            default:
                HandlerEvent(n);
                break;
            }
        }
    }
    ~EpollServer()
    {
        _listenSock->Close();
        if(_epfd > 0)
            ::close(_epfd);
    }
private:
    uint16_t _port;
    std::unique_ptr<Socket> _listenSock;

    int _epfd; //epoll fd

    struct epoll_event epArr[N]; 
};
